/**
 * 
 */
package jpb;

import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * Simple utility class to uniformly represent command line arguments that
 * consist of one and more than one elements, e.g. class path command in most
 * JVMs consists of the switch '-cp' followed by actual list of paths (both
 * elements must be added separately to list of {@link ProcessBuilder}
 * commands), whereas e.g. the command 'java' itself consists of only one
 * element.
 * <p>
 * For reasons explained in the documentation of {@link Jvm}, this class
 * allows for being initialized as empty and exposes method to query for such
 * state.
 * 
 * @author Dariusz Kordonski
 */
public final class CommandArg {

    private static final CommandArg EMPTY = new CommandArg();

    /**
     * Static factory for more expressive client usage.
     * 
     * @param elements elements of the command
     * @return new command argument
     */
    public static CommandArg of(String... elements) {
        return new CommandArg(elements);
    }
    
    /**
     * Static factory for list of command elements.
     * 
     * @param elements elements of the command
     * @return new command argument
     */
    public static CommandArg of(List<String> elements) {
        return new CommandArg(elements);
    }
    
    /**
     * Static factory for empty command argument instance.
     * 
     * @return empty command
     */
    public static CommandArg empty() {
        return EMPTY;
    }

    private final String[] elements;
    
    /**
     * Main constructor.
     * 
     * @param elements
     *            - list of command argument elements (in appropriate order).
     */
    public CommandArg(String... elements) {
        this.elements = elements.clone();
    }
    
    /**
     * Constructor for list of command elements.
     * 
     * @param elements
     *            - list of command argument elements (in appropriate order).
     */
    public CommandArg(List<String> elements) {
        this.elements = elements.toArray(new String[elements.size()]);
    }
    
    /**
     * Array of this command's elements.
     * 
     * @return elements of this command
     */
    public String[] elements() {
        return this.elements.clone();
    }
   
    /**
     * Checks if this command is empty (i.e. contains no elements).
     * 
     * @return <code>true</code>, if this command contains no elements, <code>false</code> otherwise
     */
    public boolean isEmpty() {
        return this.elements.length == 0;
    }
    
    /**
     * Add to list of process commands.
     * 
     * @param commands process commands to add to (must be a mutable list)
     */
    public void addTo(List<String> commands) {
        for (String elem : elements) {
            commands.add(elem);
        }
    }

    @Override
    public String toString() {
        return "CommandArg" + Arrays.toString(elements);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        CommandArg that = (CommandArg) o;
        return Arrays.equals(this.elements, that.elements);
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(elements);
    }
}
